package com.runa.rccprotocol.dto.novocon;

import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.FrameStruct;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class CJT188Struct implements FrameStruct {

    public enum DeviceType {
        HEAT_METER((byte) 0x20),
        HEAT_METER_SDT((byte) 0x20),
        HOUSE_VALVE((byte) 0x44),
        TEMP_CTRL((byte) 0x91),
        TEMP_CTRL_SPARK((byte) 0x45);

        private byte code;

        DeviceType(byte code) {
            this.code = code;
        }

        public byte getCode() {
            return code;
        }
    }

    public enum CtrlCode {
        READ((byte)0x01),
        SETTING((byte)0x04);

        private byte code;

        CtrlCode(byte code) {
            this.code = code;
        }

        public byte getCode() {
            return code;
        }
    }

    private DeviceType deviceType;

    private String address;

    private CtrlCode ctrlCode;

    private Map<Integer, byte[]> paramField = new HashMap<>(1);

    CJT188Struct(DeviceType deviceType, String address, CtrlCode ctrlCode) {
        this.deviceType = deviceType;
        this.address = address;
        this.ctrlCode = ctrlCode;
    }

    public DeviceType getDeviceType() {
        return deviceType;
    }

    public void setDeviceType(DeviceType deviceType) {
        this.deviceType = deviceType;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public CtrlCode getCtrlCode() {
        return ctrlCode;
    }

    public void setCtrlCode(CtrlCode ctrlCode) {
        this.ctrlCode = ctrlCode;
    }

    public Map<Integer, byte[]> getParamField() {
        return paramField;
    }

    public void setParamField(Integer paramId, byte[] paramVal) {
        this.paramField.put(paramId, paramVal);
    }

    @Override
    public byte[] getBuffer() {
        byte[] data = paramField();
        byte[] buffer = new byte[13 + data.length];
        buffer[0] = 0x68;
        buffer[1] = deviceType.getCode();
        switch (deviceType) {
            case HEAT_METER:
                buffer[5] = (byte) Integer.parseInt(address.substring(0, 2), 16);
                buffer[6] = (byte) Integer.parseInt(address.substring(2, 4), 16);
                buffer[7] = (byte) Integer.parseInt(address.substring(4, 6), 16);
                buffer[8] = (byte) Integer.parseInt(address.substring(6, 8), 16);
                break;
            case HEAT_METER_SDT:
                buffer[2] = (byte) Integer.parseInt(address.substring(6, 8), 16);
                buffer[3] = (byte) Integer.parseInt(address.substring(4, 6), 16);
                buffer[4] = (byte) Integer.parseInt(address.substring(2, 4), 16);
                buffer[5] = (byte) Integer.parseInt(address.substring(0, 2), 16);
                buffer[7] = 0x11;
                buffer[8] = 0x11;
                break;
            case HOUSE_VALVE:
                for (int i=0; i<7; i++) {
                    buffer[i+2] = (byte) Integer.parseInt(address.substring(2*i, 2*i+2), 16);
                }
                break;
            case TEMP_CTRL:
                buffer[2] = (byte) Integer.parseInt(address.substring(6, 8), 16);
                buffer[3] = (byte) Integer.parseInt(address.substring(4, 6), 16);
                buffer[4] = (byte) Integer.parseInt(address.substring(2, 4), 16);
                buffer[5] = (byte) Integer.parseInt(address.substring(0, 2), 16);
                buffer[7] = 0x3d;
                buffer[8] = 0x3d;
                break;
            case TEMP_CTRL_SPARK:
                buffer[2] = (byte) Integer.parseInt(address.substring(0, 2), 16);
                buffer[3] = (byte) Integer.parseInt(address.substring(2, 4), 16);
                buffer[4] = (byte) Integer.parseInt(address.substring(4, 6), 16);
                buffer[5] = (byte) Integer.parseInt(address.substring(6, 8), 16);
                buffer[6] = (byte) Integer.parseInt(address.substring(8, 10), 16);
                buffer[7] = 0x12;
                buffer[8] = 0x35;
                break;
        }
        buffer[9] = ctrlCode.getCode();
        buffer[10] = (byte) data.length;
        System.arraycopy(data, 0, buffer, 11, data.length);
        buffer[buffer.length - 2] = ByteUtil.sum(buffer, 0, buffer.length-2);
        buffer[buffer.length - 1] = 0x16;
        return buffer;
    }

    private byte[] paramField() {
        ByteBuffer buffer = ByteBuffer.allocate(128);
        paramField.forEach((key, val) -> {
            buffer.putShort(key.shortValue());
            if (val != null)
                buffer.put(val);
        });
        byte[] dst = new byte[buffer.position()];
        buffer.flip();
        buffer.get(dst);
        return dst;
    }

}
